/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://github.com/payara/Payara/blob/main/LICENSE.txt
 * See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at legal/OPEN-SOURCE-LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
// Portions Copyright 2018-2021 Payara Foundation and/or its affiliates
package com.sun.enterprise.iiop.security;

import com.sun.corba.ee.org.omg.CSI.ITTAnonymous;
import com.sun.corba.ee.org.omg.CSI.ITTDistinguishedName;
import com.sun.corba.ee.org.omg.CSI.ITTPrincipalName;
import com.sun.corba.ee.org.omg.CSI.ITTX509CertChain;
import com.sun.corba.ee.org.omg.CSIIOP.*;
import com.sun.corba.ee.spi.ior.IOR;
import com.sun.corba.ee.spi.ior.iiop.IIOPAddress;
import com.sun.corba.ee.spi.ior.iiop.IIOPProfileTemplate;
import com.sun.corba.ee.spi.transport.SocketInfo;
import com.sun.enterprise.common.iiop.security.AnonCredential;
import com.sun.enterprise.common.iiop.security.GSSUPName;
import com.sun.enterprise.common.iiop.security.SecurityContext;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.EjbIORConfigurationDescriptor;
import com.sun.enterprise.security.SecurityServicesUtil;
import com.sun.enterprise.security.auth.login.DistinguishedPrincipalCredential;
import com.sun.enterprise.security.auth.login.LoginContextDriver;
import com.sun.enterprise.security.auth.login.common.LoginException;
import com.sun.enterprise.security.auth.login.common.PasswordCredential;
import com.sun.enterprise.security.auth.login.common.X509CertificateCredential;
import com.sun.enterprise.security.auth.realm.Realm;
import com.sun.enterprise.security.common.ClientSecurityContext;
import com.sun.enterprise.security.ssl.SSLUtils;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.util.Utility;
import com.sun.logging.LogDomains;
import org.glassfish.api.admin.ProcessEnvironment;
import org.glassfish.api.admin.ProcessEnvironment.ProcessType;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.enterprise.iiop.api.GlassFishORBHelper;
import org.glassfish.enterprise.iiop.api.ProtocolManager;
import org.glassfish.enterprise.iiop.impl.GlassFishORBManager;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.internal.api.ORBLocator;
import org.ietf.jgss.Oid;
import org.jvnet.hk2.annotations.Service;
import org.omg.CORBA.ORB;

import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import java.net.Socket;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import static com.sun.enterprise.security.common.SecurityConstants.USERNAME_PASSWORD;
import static com.sun.logging.LogDomains.SECURITY_LOGGER;
import static java.util.logging.Level.FINE;

// GSS Related Functionality

/**
 * This class is responsible for making various decisions for selecting security information to be
 * sent in the IIOP message based on target configuration and client policies. Note: This class can
 * be called concurrently by multiple client threads. However, none of its methods need to be
 * synchronized because the methods either do not modify state or are idempotent.
 *
 * @author Nithya Subramanian
 *
 */

@Service
@Singleton
public final class SecurityMechanismSelector implements PostConstruct {

    private static final Logger _logger = LogDomains.getLogger(SecurityMechanismSelector.class, SECURITY_LOGGER);

    public static final String CLIENT_CONNECTION_CONTEXT = "ClientConnContext";

    private Set<EjbIORConfigurationDescriptor> corbaIORDescSet;
    private boolean sslRequired;
    private static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(SecServerRequestInterceptor.class);

    // A reference to POAProtocolMgr will be obtained dynamically
    // and set if not null. So set it to null here.
    private ProtocolManager protocolMgr;

    @Inject
    private SSLUtils sslUtils;

    private GlassFishORBHelper orbHelper;

    // private CompoundSecMech mechanism = null;
    private ORB orb;
    private CSIV2TaggedComponentInfo ctc;

    @Inject
    private ProcessEnvironment processEnv;

    /**
     * Read the client and server preferences from the config files.
     */
    public SecurityMechanismSelector() {
    }

    @Override
    public void postConstruct() {
        try {
            orbHelper = Lookups.getGlassFishORBHelper();
            // Initialize client security config
            String s = (orbHelper.getCSIv2Props()).getProperty(ORBLocator.ORB_SSL_CLIENT_REQUIRED);
            if (s != null && s.equals("true")) {
                sslRequired = true;
            }

            // initialize corbaIORDescSet with security config for CORBA objects
            corbaIORDescSet = new HashSet<EjbIORConfigurationDescriptor>();
            EjbIORConfigurationDescriptor iorDesc = new EjbIORConfigurationDescriptor();
            EjbIORConfigurationDescriptor iorDesc2 = new EjbIORConfigurationDescriptor();
            String serverSslReqd = (orbHelper.getCSIv2Props()).getProperty(ORBLocator.ORB_SSL_SERVER_REQUIRED);
            if (serverSslReqd != null && serverSslReqd.equals("true")) {
                iorDesc.setIntegrity(EjbIORConfigurationDescriptor.REQUIRED);
                iorDesc.setConfidentiality(EjbIORConfigurationDescriptor.REQUIRED);
                iorDesc2.setIntegrity(EjbIORConfigurationDescriptor.REQUIRED);
                iorDesc2.setConfidentiality(EjbIORConfigurationDescriptor.REQUIRED);
            }
            String clientAuthReq = (orbHelper.getCSIv2Props()).getProperty(ORBLocator.ORB_CLIENT_AUTH_REQUIRED);
            if (clientAuthReq != null && clientAuthReq.equals("true")) {
                // Need auth either by SSL or username-password.
                // This sets SSL clientauth to required.
                iorDesc.setEstablishTrustInClient(EjbIORConfigurationDescriptor.REQUIRED);
                // This sets username-password auth to required.
                iorDesc2.setAuthMethodRequired(true);
                getCorbaIORDescSet().add(iorDesc2);
            }
            getCorbaIORDescSet().add(iorDesc);

        } catch (Exception e) {
            _logger.log(Level.SEVERE, "iiop.Exception", e);
        }
    }

    public ConnectionContext getClientConnectionContext() {
        Hashtable h = ConnectionExecutionContext.getContext();
        ConnectionContext scc = (ConnectionContext) h.get(CLIENT_CONNECTION_CONTEXT);
        return scc;
    }

    public void setClientConnectionContext(ConnectionContext scc) {
        Hashtable h = ConnectionExecutionContext.getContext();
        h.put(CLIENT_CONNECTION_CONTEXT, scc);
    }

    /**
     * This method determines if SSL should be used to connect to the target based on client and target
     * policies. It will return null if SSL should not be used or an SocketInfo containing the SSL port
     * if SSL should be used.
     */
    public SocketInfo getSSLPort(IOR ior, ConnectionContext ctx) {
        SocketInfo info = null;
        CompoundSecMech mechanism = null;
        try {
            mechanism = selectSecurityMechanism(ior);
        } catch (SecurityMechanismException sme) {
            throw new RuntimeException(sme.getMessage());
        }
        ctx.setIOR(ior);
        ctx.setMechanism(mechanism);

        TLS_SEC_TRANS ssl = null;
        if (mechanism != null) {
            ssl = getCtc().getSSLInformation(mechanism);
        }

        if (ssl == null) {
            if (isSslRequired()) {
                // Attempt to create SSL connection to host, ORBInitialPort
                IIOPProfileTemplate templ = (IIOPProfileTemplate) ior.getProfile().getTaggedProfileTemplate();
                IIOPAddress addr = templ.getPrimaryAddress();
                info = IORToSocketInfoImpl.createSocketInfo("SecurityMechanismSelector1", "SSL", addr.getHost(),
                        orbHelper.getORBPort(orbHelper.getORB()));
                return info;
            } else {
                return null;
            }
        }

        int targetRequires = ssl.target_requires;
        int targetSupports = ssl.target_supports;

        /*
         * If target requires any of Integrity, Confidentiality or EstablishTrustInClient, then SSL is used.
         */
        if (isSet(targetRequires, Integrity.value) || isSet(targetRequires, Confidentiality.value)
                || isSet(targetRequires, EstablishTrustInClient.value)) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Target requires SSL");
            }
            ctx.setSSLUsed(true);
            String type = "SSL";
            if (isSet(targetRequires, EstablishTrustInClient.value)) {
                type = "SSL_MUTUALAUTH";
                ctx.setSSLClientAuthenticationOccurred(true);
            }

            if (ssl.addresses.length == 0 && GlassFishORBManager.disableSSLCheck()) {
                return null;
            }

            short sslport = ssl.addresses[0].port;
            int ssl_port = Utility.shortToInt(sslport);
            String host_name = ssl.addresses[0].host_name;

            info = IORToSocketInfoImpl.createSocketInfo("SecurityMechanismSelector2", type, host_name, ssl_port);

            return info;
        } else if (isSet(targetSupports, Integrity.value) || isSet(targetSupports, Confidentiality.value)
                || isSet(targetSupports, EstablishTrustInClient.value)) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Target supports SSL");
            }

            if (isSslRequired()) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "Client is configured to require SSL for the target");
                }

                ctx.setSSLUsed(true);

                if (ssl.addresses.length == 0 && GlassFishORBManager.disableSSLCheck()) {
                    return null;
                }

                short sslport = ssl.addresses[0].port;
                String host_name = ssl.addresses[0].host_name;
                int ssl_port = Utility.shortToInt(sslport);
                info = IORToSocketInfoImpl.createSocketInfo("SecurityMechanismSelector3", "SSL", host_name, ssl_port);
                return info;
            } else {
                return null;
            }
        } else if (isSslRequired()) {
            throw new RuntimeException("SSL required by client but not supported by server.");
        } else {
            return null;
        }
    }

    /*
     * public String[] getServerTrustedHosts() { return serverTrustedHosts; } public void
     * setServerTrustedHosts(String[] val) { this.serverTrustedHosts = val; }
     */

    public ORB getOrb() {
        return orb;
    }

    public void setOrb(ORB val) {
        this.orb = val;
    }

    public synchronized CSIV2TaggedComponentInfo getCtc() {
        if (ctc == null) {
            ctc = new CSIV2TaggedComponentInfo(orbHelper.getORB());
        }
        return ctc;
    }

    public java.util.List<SocketInfo> getSSLPorts(IOR ior, ConnectionContext ctx) {
        CompoundSecMech mechanism = null;
        try {
            mechanism = selectSecurityMechanism(ior);
        } catch (SecurityMechanismException sme) {
            throw new RuntimeException(sme.getMessage());
        }
        ctx.setIOR(ior);
        ctx.setMechanism(mechanism);

        TLS_SEC_TRANS ssl = null;
        if (mechanism != null) {
            ssl = getCtc().getSSLInformation(mechanism);
        }

        if (ssl == null) {
            if (isSslRequired()) {
                // Attempt to create SSL connection to host, ORBInitialPort
                IIOPProfileTemplate templ = (IIOPProfileTemplate) ior.getProfile().getTaggedProfileTemplate();
                IIOPAddress addr = templ.getPrimaryAddress();
                SocketInfo info = IORToSocketInfoImpl.createSocketInfo("SecurityMechanismSelector1", "SSL", addr.getHost(),
                        orbHelper.getORBPort(orbHelper.getORB()));
                // SocketInfo[] sInfos = new SocketInfo[]{info};
                List<SocketInfo> sInfos = new ArrayList<SocketInfo>();
                sInfos.add(info);
                return sInfos;
            } else {
                return null;
            }
        }

        int targetRequires = ssl.target_requires;
        int targetSupports = ssl.target_supports;

        /*
         * If target requires any of Integrity, Confidentiality or EstablishTrustInClient, then SSL is used.
         */
        if (isSet(targetRequires, Integrity.value) || isSet(targetRequires, Confidentiality.value)
                || isSet(targetRequires, EstablishTrustInClient.value)) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Target requires SSL");
            }
            ctx.setSSLUsed(true);
            String type = "SSL";
            if (isSet(targetRequires, EstablishTrustInClient.value)) {
                type = "SSL_MUTUALAUTH";
                ctx.setSSLClientAuthenticationOccurred(true);
            }
            // SocketInfo[] socketInfos = new SocketInfo[ssl.addresses.size];
            List<SocketInfo> socketInfos = new ArrayList<SocketInfo>();
            for (int addressIndex = 0; addressIndex < ssl.addresses.length; addressIndex++) {
                short sslport = ssl.addresses[addressIndex].port;
                int ssl_port = Utility.shortToInt(sslport);
                String host_name = ssl.addresses[addressIndex].host_name;

                SocketInfo sInfo = IORToSocketInfoImpl.createSocketInfo("SecurityMechanismSelector2", type, host_name, ssl_port);
                socketInfos.add(sInfo);
            }
            if (GlassFishORBManager.disableSSLCheck() && socketInfos.isEmpty()) {
                return null;
            }
            return socketInfos;
        } else if (isSet(targetSupports, Integrity.value) || isSet(targetSupports, Confidentiality.value)
                || isSet(targetSupports, EstablishTrustInClient.value)) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Target supports SSL");
            }

            if (isSslRequired()) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "Client is configured to require SSL for the target");
                }

                ctx.setSSLUsed(true);
                // SocketInfo[] socketInfos = new SocketInfo[ssl.addresses.size];
                List<SocketInfo> socketInfos = new ArrayList<SocketInfo>();
                for (int addressIndex = 0; addressIndex < ssl.addresses.length; addressIndex++) {
                    short sslport = ssl.addresses[addressIndex].port;
                    int ssl_port = Utility.shortToInt(sslport);
                    String host_name = ssl.addresses[addressIndex].host_name;

                    SocketInfo sInfo = IORToSocketInfoImpl.createSocketInfo("SecurityMechanismSelector3", "SSL", host_name,
                            ssl_port);
                    socketInfos.add(sInfo);
                }
                if (GlassFishORBManager.disableSSLCheck() && socketInfos.isEmpty()) {
                    return null;
                }
                return socketInfos;
            } else {
                return null;
            }
        } else if (isSslRequired()) {
            throw new RuntimeException("SSL required by client but not supported by server.");
        } else {
            return null;
        }
    }

    /**
     * Select the security context to be used by the CSIV2 layer based on whether the current component
     * is an application client or a web/EJB component.
     */

    public SecurityContext selectSecurityContext(IOR ior)
            throws InvalidIdentityTokenException, InvalidMechanismException, SecurityMechanismException {
        SecurityContext context = null;
        ConnectionContext cc = new ConnectionContext();
        // print CSIv2 mechanism definition in IOR
        if (traceIORs()) {
            _logger.info("\nCSIv2 Mechanism List:" + getSecurityMechanismString(ctc, ior));
        }

        getSSLPort(ior, cc);
        setClientConnectionContext(cc);

        CompoundSecMech mechanism = cc.getMechanism();
        if (mechanism == null) {
            return null;
        }
        boolean sslUsed = cc.getSSLUsed();
        boolean clientAuthOccurred = cc.getSSLClientAuthenticationOccurred();

        // Standalone client
        if (isNotServerOrACC()) {
            context = getSecurityContextForAppClient(null, sslUsed, clientAuthOccurred, mechanism);
            return context;
        }

        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "SSL used:" + sslUsed + " SSL Mutual auth:" + clientAuthOccurred);
        }
        ComponentInvocation ci = null;

        if (isACC()) {
            context = getSecurityContextForAppClient(ci, sslUsed, clientAuthOccurred, mechanism);
        } else {
            context = getSecurityContextForWebOrEJB(ci, sslUsed, clientAuthOccurred, mechanism);
        }

        return context;
    }

    /**
     * Create the security context to be used by the CSIV2 layer to marshal in the service context of
     * the IIOP message from an appclient or standalone client.
     *
     * @return the security context.
     */
    public SecurityContext getSecurityContextForAppClient(ComponentInvocation ci, boolean sslUsed, boolean clientAuthOccurred,
            CompoundSecMech mechanism)
            throws InvalidMechanismException, InvalidIdentityTokenException, SecurityMechanismException {

        return sendUsernameAndPassword(ci, sslUsed, clientAuthOccurred, mechanism);
    }

    /**
     * Create the security context to be used by the CSIV2 layer to marshal in the service context of
     * the IIOP message from an web component or EJB invoking another EJB.
     *
     * @return the security context.
     */
    public SecurityContext getSecurityContextForWebOrEJB(ComponentInvocation ci, boolean sslUsed, boolean clientAuthOccurred,
            CompoundSecMech mechanism) throws InvalidMechanismException, InvalidIdentityTokenException, SecurityMechanismException {

        SecurityContext ctx = null;
        if (!sslUsed) {
            ctx = propagateIdentity(false, ci, mechanism);
        } else {
            ctx = propagateIdentity(clientAuthOccurred, ci, mechanism);
        }
        return ctx;
    }

    Object getSSLSocketInfo(Object ior) {
        ConnectionContext ctx = new ConnectionContext();
        List<SocketInfo> socketInfo = getSSLPorts((com.sun.corba.ee.spi.ior.IOR) ior, ctx);
        setClientConnectionContext(ctx);
        return socketInfo;
    }

    private boolean isMechanismSupported(SAS_ContextSec sas) {
        byte[][] mechanisms = sas.supported_naming_mechanisms;
        byte[] mechSupported = GSSUtils.getMechanism();

        if (mechanisms == null) {
            return false;
        }

        for (int i = 0; i < mechanisms.length; i++) {
            if (Arrays.equals(mechSupported, mechanisms[i])) {
                return true;
            }
        }
        return false;
    }

    public boolean isIdentityTypeSupported(SAS_ContextSec sas) {
        int ident_token = sas.supported_identity_types;
        // the identity token matches atleast one of the types we support
        int value = ident_token & CSIV2TaggedComponentInfo.SUPPORTED_IDENTITY_TOKEN_TYPES;
        if (value != 0)
            return true;
        else
            return false;
    }

    /**
     * Get the security context to send username and password in the service context.
     *
     * @param whether username/password will be sent over plain IIOP or over IIOP/SSL.
     * @return the security context.
     * @exception SecurityMechanismException if there was an error.
     */
    private SecurityContext sendUsernameAndPassword(ComponentInvocation ci, boolean sslUsed, boolean clientAuthOccurred,
            CompoundSecMech mechanism) throws SecurityMechanismException {
        SecurityContext ctx = null;
        if (mechanism == null) {
            return null;
        }
        AS_ContextSec asContext = mechanism.as_context_mech;
        if (isSet(asContext.target_requires, EstablishTrustInClient.value)
                || (isSet(mechanism.target_requires, EstablishTrustInClient.value) && !clientAuthOccurred)) {

            ctx = getUsernameAndPassword(ci, mechanism);

            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Sending Username/Password");
            }
        } else {
            return null;
        }
        return ctx;
    }

    /**
     * Get the security context to propagate principal/distinguished name in the service context.
     *
     * @param clientAuth whether SSL client authentication has happened.
     * @return the security context.
     * @exception SecurityMechanismException if there was an error.
     */
    private SecurityContext propagateIdentity(boolean clientAuth, ComponentInvocation ci, CompoundSecMech mechanism)
            throws InvalidIdentityTokenException, InvalidMechanismException, SecurityMechanismException {

        SecurityContext ctx = null;
        if (mechanism == null) {
            return null;
        }
        AS_ContextSec asContext = mechanism.as_context_mech;
        SAS_ContextSec sasContext = mechanism.sas_context_mech;
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "SAS CONTEXT's target_requires=" + sasContext.target_requires);
            _logger.log(Level.FINE, "SAS CONTEXT's target_supports=" + sasContext.target_supports);
        }

        if (isSet(asContext.target_requires, EstablishTrustInClient.value)) {
            ctx = getUsernameAndPassword(ci, mechanism);
            if (ctx.authcls == null) { // run as mode cannot send password
                String errmsg = localStrings.getLocalString("securitymechansimselector.runas_cannot_propagate_username_password",
                        "Cannot propagate username/password required by target when using run as identity");

                _logger.log(Level.SEVERE, "iiop.runas_error", errmsg);
                throw new SecurityMechanismException(errmsg);
            }
        } else if (isSet(sasContext.target_supports, IdentityAssertion.value)
                || isSet(sasContext.target_requires, IdentityAssertion.value)) {
            // called from the client side. thus before getting the identity. check the
            // mechanisms and the identity token supported
            if (!isIdentityTypeSupported(sasContext)) {
                String errmsg = localStrings.getLocalString("securitymechanismselector.invalid_identity_type",
                        "The given identity token is unsupported.");
                throw new InvalidIdentityTokenException(errmsg);
            }
            if (sasContext.target_supports == IdentityAssertion.value) {
                if (!isMechanismSupported(sasContext)) {
                    String errmsg = localStrings.getLocalString("securitymechanismselector.invalid_mechanism",
                            "The given mechanism type is unsupported.");
                    _logger.log(Level.SEVERE, "iiop.unsupported_type_error", errmsg);
                    throw new InvalidMechanismException(errmsg);
                }
            }

            // propagate principal/certificate/distinguished name
            ctx = getIdentity();
        } else if (isSet(asContext.target_supports, EstablishTrustInClient.value)) {
            if (clientAuth) { // client auth done we can send password
                ctx = getUsernameAndPassword(ci, mechanism);
                if (ctx.authcls == null) {
                    return null; // runas mode dont have username/password
                                 // dont really need to send it too
                }
            } else { // not sending anything for unauthenticated client
                return null;
            }
        } else {
            return null; // will never come here
        }
        return ctx;
    }

    /**
     * Get the username and password either from the JAAS subject or from thread local storage. For
     * appclients if login has'nt happened this method would trigger login and popup a user interface to
     * gather authentication information.
     *
     * @return the security context.
     */
    private SecurityContext getUsernameAndPassword(ComponentInvocation ci, CompoundSecMech mechanism)
            throws SecurityMechanismException {
        try {
            Subject s = null;
            if (isNotServerOrACC()) {
                // Standalone client ... Changed the security context
                // from which to fetch the subject
                ClientSecurityContext sc = ClientSecurityContext.getCurrent();
                if (sc == null) {
                    return null;
                }
                s = sc.getSubject();
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "SUBJECT:" + s);
                }
            } else {
                if (isACC()) {
                    // get the subject
                    ClientSecurityContext sc = ClientSecurityContext.getCurrent();
                    if (sc == null) {
                        s = LoginContextDriver.doClientLogin(USERNAME_PASSWORD,
                                SecurityServicesUtil.getInstance().getCallbackHandler());
                    } else {
                        s = sc.getSubject();
                    }
                } else {
                    // web/ejb
                    s = getSubjectFromSecurityCurrent();
                    // TODO check if username/password is available
                    // if not throw exception
                }
            }
            SecurityContext ctx = new SecurityContext();
            final Subject sub = s;
            ctx.subject = s;
            // determining if run-as has been used
            Set<PasswordCredential> privateCredSet = AccessController.doPrivileged(new PrivilegedAction<Set>() {

                @Override
                public Set run() {
                    return sub.getPrivateCredentials(PasswordCredential.class);
                }
            });
            if (privateCredSet.isEmpty()) { // this is runas case dont set
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "no private credential run as mode");
                }
                ctx.authcls = null; // the auth class
                ctx.identcls = GSSUPName.class;

            } else {
                /**
                 * lookup the realm name that is required by the server and set it up in the PasswordCredential
                 * class.
                 */
                AS_ContextSec asContext = mechanism.as_context_mech;
                final byte[] target_name = asContext.target_name;
                byte[] _realm = null;
                if (target_name == null || target_name.length == 0) {
                    _realm = Realm.getDefaultRealm().getBytes();
                } else {
                    _realm = GSSUtils.importName(GSSUtils.GSSUP_MECH_OID, target_name);
                }
                final String realm_name = new String(_realm);
                final Iterator it = privateCredSet.iterator();
                for (; it.hasNext();) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public java.lang.Object run() {
                            PasswordCredential pc = (PasswordCredential) it.next();
                            pc.setRealm(realm_name);
                            return null;
                        }
                    });
                }
                ctx.authcls = PasswordCredential.class;
            }
            return ctx;
        } catch (LoginException le) {
            throw le;
        } catch (Exception e) {
            _logger.log(Level.SEVERE, "iiop.user_password_exception", e);
            return null;
        }
    }

    /**
     * Get the principal/distinguished name from thread local storage.
     *
     * @return the security context.
     */
    private SecurityContext getIdentity() throws SecurityMechanismException {
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "Getting PRINCIPAL/DN from TLS");
        }

        SecurityContext ctx = new SecurityContext();
        final SecurityContext sCtx = ctx;
        // get stuff from the SecurityContext class
        com.sun.enterprise.security.SecurityContext scontext = com.sun.enterprise.security.SecurityContext.getCurrent();
        if ((scontext == null) || scontext.didServerGenerateCredentials()) {

            // a default guest/guest123 was created
            sCtx.identcls = AnonCredential.class;

            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public java.lang.Object run() {
                    // remove all the public and private credentials
                    Subject sub = new Subject();
                    sCtx.subject = sub;
                    sCtx.subject.getPublicCredentials().add(new AnonCredential());
                    return null;
                }
            });
            return sCtx;
        }

        Subject s = getSubjectFromSecurityCurrent();
        ctx.subject = s;

        // Figure out the credential class
        final Subject sub = s;
        Set<PasswordCredential> credSet = AccessController.doPrivileged(new PrivilegedAction<Set>() {
            @Override
            public Set run() {
                return sub.getPrivateCredentials(PasswordCredential.class);
            }
        });
        if (credSet.size() == 1) {
            ctx.identcls = GSSUPName.class;
            final Set cs = credSet;
            Subject subj = AccessController.doPrivileged(new PrivilegedAction<Subject>() {
                @Override
                public Subject run() {
                    Subject ss = new Subject();
                    Iterator<PasswordCredential> iter = cs.iterator();
                    PasswordCredential pc = iter.next();
                    GSSUPName gssname = new GSSUPName(pc.getUser(), pc.getRealm());
                    ss.getPublicCredentials().add(gssname);
                    return ss;
                }
            });
            ctx.subject = subj;
            return ctx;
        }

        Set pubCredSet = s.getPublicCredentials();
        if (pubCredSet.size() != 1) {
            _logger.log(Level.SEVERE, "iiop.principal_error");
            return null;
        } else {
            Iterator credIter = pubCredSet.iterator();
            if (credIter.hasNext()) {
                Object o = credIter.next();
                if (o instanceof GSSUPName) {
                    ctx.identcls = GSSUPName.class;
                } else if (o instanceof X500Principal) {
                    ctx.identcls = X500Principal.class;
                } else if (o instanceof DistinguishedPrincipalCredential) {
                    ctx.identcls = DistinguishedPrincipalCredential.class;
                } else {
                    ctx.identcls = X509CertificateCredential.class;
                }
            } else {
                _logger.log(Level.SEVERE, "iiop.credential_error");
                return null;
            }
        }
        return ctx;
    }

    private Subject getSubjectFromSecurityCurrent() throws SecurityMechanismException {
        com.sun.enterprise.security.SecurityContext sc = null;
        sc = com.sun.enterprise.security.SecurityContext.getCurrent();
        if (sc == null) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, " SETTING GUEST ---");
            }
            sc = com.sun.enterprise.security.SecurityContext.init();
        }
        if (sc == null) {
            throw new SecurityMechanismException("Could not find " + " security information");
        }
        Subject s = sc.getSubject();
        if (s == null) {
            throw new SecurityMechanismException("Could not find " + " subject information in the security context.");
        }
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "Subject in security current:" + s);
        }
        return s;
    }

    public CompoundSecMech selectSecurityMechanism(IOR ior) throws SecurityMechanismException {
        CompoundSecMech[] mechList = getCtc().getSecurityMechanisms(ior);
        CompoundSecMech mech = selectSecurityMechanism(mechList);
        return mech;
    }

    /**
     * Select the security mechanism from the list of compound security mechanisms.
     */
    private CompoundSecMech selectSecurityMechanism(CompoundSecMech[] mechList) throws SecurityMechanismException {
        // We should choose from list of compound security mechanisms
        // which are in decreasing preference order. Right now we select
        // the first one.
        if (mechList == null || mechList.length == 0) {
            return null;
        }
        CompoundSecMech mech = null;
        for (int i = 0; i < mechList.length; i++) {
            mech = mechList[i];
            boolean useMech = useMechanism(mech);
            if (useMech) {
                return mech;
            }
        }
        throw new SecurityMechanismException("Cannot use any of the " + " target's supported mechanisms");
    }

    private boolean useMechanism(CompoundSecMech mech) {
        boolean val = true;
        TLS_SEC_TRANS tls = getCtc().getSSLInformation(mech);

        if (mech.sas_context_mech.supported_naming_mechanisms.length > 0 && !isMechanismSupported(mech.sas_context_mech)) {
            return false;
        } else if (mech.as_context_mech.client_authentication_mech.length > 0 && !isMechanismSupportedAS(mech.as_context_mech)) {
            return false;
        }

        if (tls == null) {
            return true;
        }
        int targetRequires = tls.target_requires;
        if (isSet(targetRequires, EstablishTrustInClient.value)) {
            if (!sslUtils.isKeyAvailable()) {
                val = false;
            }
        }
        return val;
    }

    private boolean isMechanismSupportedAS(AS_ContextSec as) {
        byte[] mechanism = as.client_authentication_mech;
        byte[] mechSupported = GSSUtils.getMechanism();

        if (mechanism == null) {
            return false;
        }

        if (Arrays.equals(mechanism, mechSupported)) {
            return true;
        }

        return false;
    }

    // Returns the target_name from PasswordCredential in Subject subj
    // subj must contain a single instance of PasswordCredential.

    private byte[] getTargetName(Subject subj) {

        byte[] tgt_name = {};

        final Subject sub = subj;
        final Set<PasswordCredential> credset = AccessController.doPrivileged(new PrivilegedAction<Set>() {
            @Override
            public Set run() {
                return sub.getPrivateCredentials(PasswordCredential.class);
            }
        });
        if (credset.size() == 1) {
            tgt_name = AccessController.doPrivileged(new PrivilegedAction<byte[]>() {
                @Override
                public byte[] run() {
                    Iterator<PasswordCredential> iter = credset.iterator();
                    PasswordCredential pc = iter.next();
                    return pc.getTargetName();
                }
            });
        }
        return tgt_name;
    }

    private boolean evaluate_client_conformance_ssl(EjbIORConfigurationDescriptor iordesc, boolean sslUsed, X509Certificate[] certchain) {
        try {
            _logger.log(FINE, "SecurityMechanismSelector.evaluate_client_conformance_ssl->:");

            boolean sslRequired = false;
            boolean sslSupported = false;
            int ssl_target_requires = 0;
            int ssl_target_supports = 0;

            /*************************************************************************
             * Conformance Matrix:
             *
             * |---------------|---------------------|---------------------|------------|
             * | SSLClientAuth | targetrequires.ETIC | targetSupports.ETIC | Conformant |
             * |---------------|---------------------|---------------------|------------|
             * |     Yes       |          0          |      1              |    Yes     |
             * |     Yes       |          0          |      0              |    No      |
             * |     Yes       |          1          |      X              |    Yes     |
             * |     No        |          0          |      X              |    Yes     |
             * |     No        |          1          |      X              |    No      |
             * |---------------|---------------------|---------------------|------------|
             *
             *************************************************************************/

            // gather the configured SSL security policies.

            ssl_target_requires = getCtc().getTargetRequires(iordesc);
            ssl_target_supports = getCtc().getTargetSupports(iordesc);

            if (isSet(ssl_target_requires, Integrity.value) || isSet(ssl_target_requires, Confidentiality.value)
                    || isSet(ssl_target_requires, EstablishTrustInClient.value))
                sslRequired = true;
            else
                sslRequired = false;

            if (ssl_target_supports != 0)
                sslSupported = true;
            else
                sslSupported = false;

            /*
             * Check for conformance for using SSL usage. a. if SSL was used, then either the target must
             * require or support SSL. In the latter case, SSL is used because of client policy. b. if SSL was
             * not used, then the target must not require it either. The target may or may not support SSL (it
             * is irrelevant).
             */
            if (_logger.isLoggable(FINE)) {
                _logger.log(FINE, "SecurityMechanismSelector.evaluate_client_conformance_ssl:" + " " +
                        isSet(ssl_target_requires, Integrity.value) + " " +
                        isSet(ssl_target_requires, Confidentiality.value) + " " +
                        isSet(ssl_target_requires, EstablishTrustInClient.value) + " " +
                        sslRequired + " " + sslSupported + " " +
                        sslUsed);
            }

            if (sslUsed) {
                if (!(sslRequired || sslSupported))
                    return false; // security mechanism did not match
            } else {
                if (sslRequired)
                    return false; // security mechanism did not match
            }

            /*
             * Check for conformance for SSL client authentication. a. if client performed SSL client
             * authentication, then the target must either require or support SSL client authentication. If the
             * target only supports, SSL client authentication is used because of client security policy. b. if
             * SSL client authentication was not used, then the target must not require SSL client authentcation
             * either. The target may or may not support SSL client authentication (it is irrelevant).
             */

            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE,
                        "SecurityMechanismSelector.evaluate_client_conformance_ssl:" + " "
                                + isSet(ssl_target_requires, EstablishTrustInClient.value) + " "
                                + isSet(ssl_target_supports, EstablishTrustInClient.value));
            }

            if (certchain != null) {
                if (!(isSet(ssl_target_requires, EstablishTrustInClient.value)
                        || isSet(ssl_target_supports, EstablishTrustInClient.value)))
                    return false; // security mechanism did not match
            } else {
                if (isSet(ssl_target_requires, EstablishTrustInClient.value))
                    return false; // security mechanism did not match
            }

            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "SecurityMechanismSelector.evaluate_client_conformance_ssl: true");
            }

            return true; // mechanism matched
        } finally {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "SecurityMechanismSelector.evaluate_client_conformance_ssl<-:");
            }
        }
    }

    /*
     * Evaluates a client's conformance to a security policies at the client authentication layer.
     * returns true if conformant ; else returns false
     */
    private boolean evaluate_client_conformance_ascontext(SecurityContext ctx, EjbIORConfigurationDescriptor iordesc,
            String realmName) {

        boolean client_authenticated = false;

        // get requirements and supports at the client authentication layer
        AS_ContextSec ascontext = null;
        try {
            ascontext = this.getCtc().createASContextSec(iordesc, realmName);
        } catch (Exception e) {
            _logger.log(Level.SEVERE, "iiop.createcontextsec_exception", e);

            return false;
        }

        /*************************************************************************
         * Conformance Matrix:
         *
         * |------------|---------------------|---------------------|------------|
         * | ClientAuth | targetrequires.ETIC | targetSupports.ETIC | Conformant |
         * |------------|---------------------|---------------------|------------|
         * |     Yes    |          0          |      1              |    Yes     |
         * |     Yes    |          0          |      0              |    No      |
         * |     Yes    |          1          |      X              |    Yes     |
         * |     No     |          0          |      X              |    Yes     |
         * |     No     |          1          |      X              |    No      |
         * |------------|---------------------|---------------------|------------|
         *
         * Abbreviations: ETIC - EstablishTrusInClient
         *
         *************************************************************************/

        if ((ctx != null) && (ctx.authcls != null) && (ctx.subject != null))
            client_authenticated = true;
        else
            client_authenticated = false;

        if (client_authenticated) {
            if (!(isSet(ascontext.target_requires, EstablishTrustInClient.value)
                    || isSet(ascontext.target_supports, EstablishTrustInClient.value))) {
                return false; // non conforming client
            }
            // match the target_name from client with the target_name in policy

            byte[] client_tgtname = getTargetName(ctx.subject);

            if (ascontext.target_name.length != client_tgtname.length) {
                return false; // mechanism did not match.
            }
            for (int i = 0; i < ascontext.target_name.length; i++)
                if (ascontext.target_name[i] != client_tgtname[i]) {
                    return false; // mechanism did not match
                }
        } else {
            if (isSet(ascontext.target_requires, EstablishTrustInClient.value)) {
                return false; // no mechanism match.
            }
        }
        return true;
    }

    /*
     * Evaluates a client's conformance to a security policy at the sas context layer. The security
     * policy is derived from the EjbIORConfigurationDescriptor. returns true if conformant ; else
     * returns false
     */
    private boolean evaluate_client_conformance_sascontext(SecurityContext ctx, EjbIORConfigurationDescriptor iordesc) {

        boolean caller_propagated = false;

        // get requirements and supports at the sas context layer
        SAS_ContextSec sascontext = null;
        try {
            sascontext = this.getCtc().createSASContextSec(iordesc);
        } catch (Exception e) {
            _logger.log(Level.SEVERE, "iiop.createcontextsec_exception", e);
            return false;
        }

        if ((ctx != null) && (ctx.identcls != null) && (ctx.subject != null))
            caller_propagated = true;
        else
            caller_propagated = false;

        if (caller_propagated) {
            if (!isSet(sascontext.target_supports, IdentityAssertion.value))
                return false; // target does not support IdentityAssertion

            /*
             * There is no need further checking here since SecServerRequestInterceptor code filters out the
             * following: a. IdentityAssertions of types other than those required by level 0 (for e.g.
             * IdentityExtension) b. unsupported identity types. The checks are done in
             * SecServerRequestInterceptor rather than here to minimize code changes.
             */
            return true;
        }
        return true; // either caller was not propagated or mechanism matched.
    }

    /**
     * Evaluates a client's conformance to the security policies configured on the target. Returns true
     * if conformant to the security policies otherwise return false.
     *
     * Conformance checking is done as follows: First, the object_id is mapped to the set of
     * EjbIORConfigurationDescriptor. Each EjbIORConfigurationDescriptor corresponds to a single
     * CompoundSecMechanism of the CSIv2 spec. A client is considered to be conformant if a
     * CompoundSecMechanism consistent with the client's actions is found i.e. transport_mech,
     * as_context_mech and sas_context_mech must all be consistent.
     *
     */
    private boolean evaluateClientConformance(SecurityContext ctx, byte[] objectId, boolean sslUsed, X509Certificate[] certchain) {
        // Obtain the IOR configuration descriptors for the Ejb using the objectId within the SecurityContext field.

        // If objectId is null then nothing to evaluate. This is a sanity check - the objectId should never be null.
        if (objectId == null) {
            return true;
        }

        if (protocolMgr == null) {
            protocolMgr = orbHelper.getProtocolManager();
        }

        // Check to make sure protocolMgr is not null.
        // This could happen during server initialization or if this call
        // is on a callback object in the client VM.
        if (protocolMgr == null) {
            return true;
        }

        EjbDescriptor ejbDesc = protocolMgr.getEjbDescriptor(objectId);

        Set<EjbIORConfigurationDescriptor> iorDescSet = null;
        if (ejbDesc != null) {
            iorDescSet = ejbDesc.getIORConfigurationDescriptors();
        } else {
            // Probably a non-EJB CORBA object.
            // Create a temporary EjbIORConfigurationDescriptor.
            iorDescSet = getCorbaIORDescSet();
        }

        if (_logger.isLoggable(FINE)) {
            _logger.log(FINE, "SecurityMechanismSelector.evaluate_client_conformance: iorDescSet: " + iorDescSet);
        }

        /*
         * if there are no IORConfigurationDescriptors configured, then no security policy is configured. So
         * consider the client to be conformant.
         */
        if (iorDescSet.isEmpty()) {
            return true;
        }

        // Go through each EjbIORConfigurationDescriptor trying to find
        // a find a CompoundSecMechanism that matches client's actions.
        boolean checkSkipped = false;
        for (Iterator itr = iorDescSet.iterator(); itr.hasNext();) {
            EjbIORConfigurationDescriptor iorDesc = (EjbIORConfigurationDescriptor) itr.next();
            if (skip_client_conformance(iorDesc)) {
                _logger.log(Level.FINE, "SecurityMechanismSelector.evaluate_client_conformance: skip_client_conformance");
                checkSkipped = true;
                continue;
            }

            if (!GlassFishORBManager.disableSSLCheck()) {
                if (!evaluate_client_conformance_ssl(iorDesc, sslUsed, certchain)) {
                    _logger.log(FINE, "SecurityMechanismSelector.evaluate_client_conformance: evaluate_client_conformance_ssl");
                    checkSkipped = false;
                    continue;
                }
            }

            String realmName = "default";

            if (ejbDesc != null && ejbDesc.getApplication() != null) {
                realmName = ejbDesc.getApplication().getRealm();
            }

            if (realmName == null) {
                realmName = iorDesc.getRealmName();
            }

            if (realmName == null) {
                realmName = "default";
            }

            if (!evaluate_client_conformance_ascontext(ctx, iorDesc, realmName)) {
                _logger.log(FINE, "SecurityMechanismSelector.evaluate_client_conformance: evaluate_client_conformance_ascontext");
                checkSkipped = false;
                continue;
            }

            if (!evaluate_client_conformance_sascontext(ctx, iorDesc)) {
                _logger.log(FINE, "SecurityMechanismSelector.evaluate_client_conformance: evaluate_client_conformance_sascontext");
                checkSkipped = false;
                continue;
            }

            return true; // security policy matched.
        }

        if (checkSkipped) {
            return true;
        }

        return false; // No matching security policy found
    }

    /**
     * if ejb requires no security - then skip checking the client-conformance
     */
    private boolean skip_client_conformance(EjbIORConfigurationDescriptor ior) {
        String none = EjbIORConfigurationDescriptor.NONE;
        // sanity check
        if (ior == null) {
            return false;
        }
        // SSL is required and/or supported either
        if (!none.equalsIgnoreCase(ior.getIntegrity())) {
            return false;
        }
        if (!none.equalsIgnoreCase(ior.getConfidentiality())) {
            return false;
        }
        if (!none.equalsIgnoreCase(ior.getEstablishTrustInClient())) {
            return false;
        }
        // Username password is required
        if (ior.isAuthMethodRequired()) {
            return false;
        }
        // caller propagation is supported
        if (!none.equalsIgnoreCase(ior.getCallerPropagation())) {
            return false;
        }
        return true;
    }

    /**
     * Called by the target to interpret client credentials after validation.
     */
    public SecurityContext evaluateTrust(SecurityContext securityContext, byte[] objectId, Socket socket) throws SecurityMechanismException {

        // sslUsed is true if SSL was used.
        boolean sslUsed = false;

        // X509 Certificicate chain is non null if client has authenticated at the SSL level.
        X509Certificate[] certChain = null;

        // First gather all the information and then check the conformance of the client to the security policies.
        // If the test for client conformance passes, then set the security context.
        if (socket instanceof SSLSocket) {
            sslUsed = true; // SSL was used

            // Check if there is a transport principal
            SSLSocket sslSock = (SSLSocket) socket;
            SSLSession sslSession = sslSock.getSession();
            try {
                certChain = (X509Certificate[]) sslSession.getPeerCertificates();
            } catch (Exception e) {
                _logger.log(FINE, "iiop.cannot_get_peercert", e);
            }
        }

        // For a local invocation - we don't need to check the security
        // policies. The following condition guarantees the call is local
        // and thus bypassing policy checks.

        // XXX: Workaround for non-null connection object ri for local invocation.
        Long clientID = ConnectionExecutionContext.readClientThreadID();
        if (clientID != null && clientID == Thread.currentThread().getId() && securityContext == null) {
            return null;
        }

        if (!evaluateClientConformance(securityContext, objectId, sslUsed, certChain)) {
            throw new SecurityMechanismException(
                "Trust evaluation failed because " +
                 "client does not conform to configured security policies");
        }

        if (securityContext == null) {
            if (socket == null || !sslUsed || certChain == null) {
                // Transport info is null and security context is null.
                // No need to set the anonymous credential here, it will get set if any security operations
                // (e.g. getCallerPrincipal) are done.
                //
                // Note: if the target object is not an EJB, no security ctx is needed.
                return null;
            } else {
                // Set the transport principal in subject and
                // return the X500Principal class
                securityContext = new SecurityContext();
                X500Principal x500principal = certChain[0].getSubjectX500Principal();
                securityContext.subject = new Subject();
                securityContext.subject.getPublicCredentials().add(x500principal);
                securityContext.identcls = X500Principal.class;
                securityContext.authcls = null;
                return securityContext;
            }
        }

        Class<?> authCls = securityContext.authcls;
        Class<?> identCls = securityContext.identcls;

        securityContext.authcls = null;
        securityContext.identcls = null;

        if (identCls != null) {
            securityContext.identcls = identCls;
        } else if (authCls != null) {
            securityContext.authcls = authCls;
        } else {
            securityContext.identcls = AnonCredential.class;
        }

        return securityContext;
    }

    private static boolean isSet(int val1, int val2) {
        if ((val1 & val2) == val2) {
            return true;
        }
        return false;
    }

    private Set<EjbIORConfigurationDescriptor> getCorbaIORDescSet() {
        return corbaIORDescSet;
    }

    public boolean isSslRequired() {
        return sslRequired;
    }

    private boolean isNotServerOrACC() {
        return processEnv.getProcessType().equals(ProcessType.Other);
    }

    private boolean isACC() {
        return processEnv.getProcessType().equals(ProcessType.ACC);
    }

    // property controls IOR tracing by clients]

    private static final String traceIORsProperty = "com.sun.enterprise.iiop.security.traceIORS";

    private static final boolean _traceIORs = Boolean.getBoolean(traceIORsProperty);

    private static final Hashtable<Integer, String> assocOptions;

    static {
        assocOptions = new Hashtable<Integer, String>();
        assocOptions.put(Integer.valueOf(Integrity.value), "Integrity");
        assocOptions.put(Integer.valueOf(Confidentiality.value), "Confidentiality");
        assocOptions.put(Integer.valueOf(EstablishTrustInTarget.value), "EstablishTrustInTarget");
        assocOptions.put(Integer.valueOf(EstablishTrustInClient.value), "EstablishTrustInClient");
        assocOptions.put(Integer.valueOf(IdentityAssertion.value), "IdentityAssertion");
        assocOptions.put(Integer.valueOf(DelegationByClient.value), "DelegationByClient");
    }

    private static final Hashtable<Integer, String> identityTokenTypes;

    static {
        identityTokenTypes = new Hashtable<Integer, String>();
        identityTokenTypes.put(Integer.valueOf(ITTAnonymous.value), "Anonymous");
        identityTokenTypes.put(Integer.valueOf(ITTPrincipalName.value), "PrincipalName");
        identityTokenTypes.put(Integer.valueOf(ITTX509CertChain.value), "X509CertChain");
        identityTokenTypes.put(Integer.valueOf(ITTDistinguishedName.value), "DistinguishedName");
    }

    public static boolean traceIORs() {
        return _traceIORs;
    }

    public String getSecurityMechanismString(CSIV2TaggedComponentInfo tCI, IOR ior) {
        // need to print out top port value and hosr ior.getProfile().isLocal();
        String typeId = ior.getTypeId();
        CompoundSecMech[] mechList = tCI.getSecurityMechanisms(ior);
        return getSecurityMechanismString(tCI, mechList, typeId);
    }

    public static String getSecurityMechanismString(CSIV2TaggedComponentInfo tCI, CompoundSecMech[] list, String name) {
        StringBuilder b = new StringBuilder();
        b.append("\ntypeId: " + name);
        try {
            for (int i = 0; list != null && i < list.length; i++) {
                CompoundSecMech m = list[i];
                b.append("\nCSIv2 CompoundSecMech[" + i + "]\n\tTarget Requires:");
                Enumeration<Integer> keys = assocOptions.keys();
                while (keys.hasMoreElements()) {
                    Integer j = keys.nextElement();
                    if (isSet(m.target_requires, j.intValue())) {
                        b.append("\n\t\t" + assocOptions.get(j));
                    }
                }

                TLS_SEC_TRANS ssl = tCI.getSSLInformation(m);
                if (ssl != null) {
                    b.append("\n\tTLS_SEC_TRANS\n\t\tTarget Requires:");
                    keys = assocOptions.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(ssl.target_requires, j.intValue())) {
                            b.append("\n\t\t\t" + assocOptions.get(j));
                        }
                    }
                    b.append("\n\t\tTarget Supports:");
                    keys = assocOptions.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(ssl.target_supports, j.intValue())) {
                            b.append("\n\t\t\t" + assocOptions.get(j));
                        }
                    }
                    TransportAddress[] aList = ssl.addresses;
                    for (int j = 0; j < aList.length; j++) {
                        TransportAddress a = aList[j];
                        b.append("\n\t\tAddress[" + j + "] Host Name: " + a.host_name + " port: " + a.port);
                    }
                }

                AS_ContextSec asContext = m.as_context_mech;
                if (asContext != null) {
                    b.append("\n\tAS_ContextSec\n\t\tTarget Requires:");
                    keys = assocOptions.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(asContext.target_requires, j.intValue())) {
                            b.append("\n\t\t\t" + assocOptions.get(j));
                        }
                    }
                    b.append("\n\t\tTarget Supports:");
                    keys = assocOptions.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(asContext.target_supports, j.intValue())) {
                            b.append("\n\t\t\t" + assocOptions.get(j));
                        }
                    }
                    try {
                        if (asContext.client_authentication_mech.length > 0) {
                            Oid oid = new Oid(asContext.client_authentication_mech);
                            b.append("\n\t\tclient_auth_mech_OID:" + oid);
                        } else {
                            b.append("\n\t\tclient_auth_mech_OID: undefined");
                        }
                    } catch (Exception e) {
                        b.append("\n\t\tclient_auth_mech_OID: (invalid)" + e.getMessage());
                    } finally {
                        b.append("\n\t\ttarget_name:" + new String(asContext.target_name));
                    }
                }

                SAS_ContextSec sasContext = m.sas_context_mech;
                if (sasContext != null) {
                    b.append("\n\tSAS_ContextSec\n\t\tTarget Requires:");
                    keys = assocOptions.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(sasContext.target_requires, j.intValue())) {
                            b.append("\n\t\t\t" + assocOptions.get(j));
                        }
                    }
                    b.append("\n\t\tTarget Supports:");
                    keys = assocOptions.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(sasContext.target_supports, j.intValue())) {
                            b.append("\n\t\t\t" + assocOptions.get(j));
                        }
                    }
                    b.append("\n\t\tprivilege authorities:" + Arrays.toString(sasContext.privilege_authorities));
                    byte[][] nameTypes = sasContext.supported_naming_mechanisms;
                    for (int j = 0; j < nameTypes.length; j++) {
                        try {
                            if (nameTypes[j].length > 0) {
                                Oid oid = new Oid(nameTypes[j]);
                                b.append("\n\t\tSupported Naming Mechanim[" + j + "]: " + oid);
                            } else {
                                b.append("\n\t\tSupported Naming Mechanim[" + j + "]:  undefined");
                            }
                        } catch (Exception e) {
                            b.append("\n\t\tSupported Naming Mechanism[" + j + "]: (invalid)" + e.getMessage());
                        }
                    }
                    b.append("\n\t\tsupported Identity Types:");
                    long map = sasContext.supported_identity_types;
                    keys = identityTokenTypes.keys();
                    while (keys.hasMoreElements()) {
                        Integer j = keys.nextElement();
                        if (isSet(sasContext.supported_identity_types, j.intValue())) {
                            b.append("\n\t\t\t" + identityTokenTypes.get(j));
                            map = map - j.intValue();
                        }
                    }
                    if (map > 0) {
                        b.append("\n\t\t\tcustom bits set: " + map);
                    }
                }
            }
            b.append("\n\n");
        } catch (Exception e) {
            e.printStackTrace();
            return ("Unexpected exception during IOR tracing - unset Property: " + traceIORsProperty);
        }
        return b.toString();
    }

}
